package com.tju.resource.business.tb_prod_plan;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tju.resource.common.ServiceException;
import com.tju.resource.mapper.*;
import com.tju.resource.model.*;
import com.tju.resource.business.sys.SysParamsService;
import com.tju.resource.business.tb_matl_store.TbMatlStoreService;
import com.tju.resource.business.tb_order.TbOrderService;
import com.tju.resource.business.tb_process_group.TbProcessGroupService;
import com.tju.resource.business.tb_send_matl.TbSendMatlService;
import com.tju.resource.result.Result;
import com.tju.resource.result.ResultEnum;
import com.tju.resource.result.ResultUtil;
import com.tju.resource.tool.tool.ChineseExceptionUtils;
import com.tju.resource.tool.tool.ClientParameters;
import com.tju.resource.tool.tool.EmptyUtils;
import com.tju.resource.tool.tool.QuickQuery;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Random;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

@Slf4j
@Service
public class TbProdPlanServiceImpl implements TbProdPlanService {

    private static int modelIndex = 0; //指令下标
    @Autowired
    TbProdPlanMapper mapper;
    @Autowired
    TbProcessGroupService pgService;
    @Autowired
    private TbOrderService tbOrderService;
    @Autowired
    private TbOrderMapper tbOrderMapper;
    @Autowired
    private TbSendMatlMapper sendMatlMapper;
    //@Autowired
    //private TbCommandMapper tbCommandMapper;
    @Autowired
    private TbConsumablesMapper tbConsumablesMapper;
    @Autowired
    private ChineseExceptionUtils zh_CH;
    @Autowired
    private TbPpConsumablesMapper tbPpConsumablesMapper;
    @Autowired
    private SysParamsService paramsServiceService;
    //@Autowired
    //private TbSharperMapper tbSharperMapper;
    @Autowired
    private TbMaterialMapper tbMaterialMapper;
    @Autowired
    private TbMatlConsumablesMapper tbMatlConsumablesMapper;
    private String[] arr = {"T-", "BU-"};
    private Lock lock = new ReentrantLock(true);
    @Autowired
    private SysUserMapper sysUserMapper;
    @Autowired
    private TbMatlStoreService tbMatlStoreService;
    @Autowired
    private TbSendMatlService tbSendMatlService;
    @Autowired
    private TbPpMatlRmMapper tbPpMatlRmMapper;

    @Override
    public TbProdPlan get(Long id) {
        return mapper.selectById(id);
    }

    @Override
    public List<TbProdPlan> getByOR(Long orderId) {
        QueryWrapper<TbProdPlan> query = new QueryWrapper<>();
        query.eq("order_id", orderId);
        query.orderByDesc("id");
        return mapper.selectList(query);
    }


    public TbProdPlan getByMatlId(Long matlId) {
        List<TbProdPlan> list = QuickQuery.list(mapper, QuickQuery.params().putOnce("matl_id", matlId));

        return list.size() == 0 ? null : list.get(0);
    }

    @Override
    public Long getProds(Long orderId) {
        List<TbProdPlan> reList;
        AtomicReference<Long> result = new AtomicReference<>(0L);
        reList = getByOR(orderId);

        if (reList.size() != 0) {
            reList.forEach(plan -> result.updateAndGet(v -> v + (null == plan.getPlanNumber() ? 0L : plan.getPlanNumber())));
        } else {
            return 0L;
        }
        return result.get();
    }

    @Override
    public Result<Object> getAll(ClientParameters params) {
        try {
            if (EmptyUtils.isNotEmpty(params.getPage())&&EmptyUtils.isNotEmpty(params.getLimit())) {
                Page<TbProdPlan> page = new Page<>(params.getPage(), params.getLimit());
                IPage<TbProdPlan> iPage = mapper.getAll(page, params);
                List<TbProdPlan> records = iPage.getRecords();
                for (TbProdPlan prodPlan : records) {
                    prodPlan.setApprove(tbSendMatlService.approvePlan(prodPlan.getId()));//审核通过
                    prodPlan.setPpConsumablesList(mapper.getTbPpConsumablesList(prodPlan.getId())); //耗材
                    prodPlan.setTbMaterial(tbMaterialMapper.selectByMatilId(prodPlan.getMatlId())); //物料
                    //未完成数  计划数-完成数 = 未完成数
                    Long notFinCount = EmptyUtils.isEmpty(prodPlan.getPlanNumber()) ? 0 : prodPlan.getPlanNumber() - (EmptyUtils.isEmpty(prodPlan.getFinCount()) ? 0 : prodPlan.getFinCount()) < 0 ? 0 : prodPlan.getPlanNumber() - (EmptyUtils.isEmpty(prodPlan.getFinCount()) ? 0 : prodPlan.getFinCount());
                    prodPlan.setNotFinCount(notFinCount); //未完成数
                }
                return ResultUtil.success(ResultEnum.SUCCESS, records, iPage.getTotal());
            }else {
                return ResultUtil.error(ResultEnum.UNKONW_ERROR, zh_CH.MissingParameters);
            }

        } catch (Exception e) {
            e.printStackTrace();
            return ResultUtil.error(ResultEnum.UNKONW_ERROR, e.getMessage());
        }
    }

    @Override
    @Transactional
    public Result<Object> add(TbProdPlan plan) {
        if (plan.getPlanNumber() <= 0) {
            throw new ServiceException("计划数不能小于0!");
        }
        if (EmptyUtils.isEmpty(plan.getDelivery())) return ResultUtil.error(ResultEnum.UNKONW_ERROR, "交期不能为空");
        TbOrder tbOrder = tbOrderService.checkOrderNumberUnique(plan.getOrderNumber());
        TbMaterial material = QuickQuery.byOne(tbMaterialMapper, "matl_number", plan.getMatlNumber());
        if (EmptyUtils.isEmpty(material)) return ResultUtil.error(ResultEnum.UNKONW_ERROR, "请选择存在的物料");
        if (material.getIsUsed() == 0) { //没使用
            material.setIsUsed(1);//使用过
            if (tbMaterialMapper.updateById(material) == 0)
                throw new ServiceException("修改使用状态失败!");
        }

        if (null == tbOrder) {
            throw new ServiceException("该订单号不存在!");
        }

        if (EmptyUtils.isNotEmpty(plan.getGroupNumber())) {
            if (EmptyUtils.isEmpty(pgService.getProcessGroupById(plan.getGroupNumber()))) {
                throw new ServiceException("该工艺流程不存在!");
            }
        }
        //if (getProds(tbOrder.getId()) + plan.getPlanNumber() <= tbOrder.getOrderPcs()) {
        String username = Objects.requireNonNull(QuickQuery.byOne(sysUserMapper, "username", plan.getCreateBy())).getDivCode();
        plan.setSpecNumber(productionModel(username));
        plan.setMatlId(material.getId());
        plan.setOrderId(tbOrder.getId());
        if (mapper.insert(plan) > 0) {
            List<TbRmMatl> tbRmMatls = tbMaterialMapper.selectTbRmMatl(material.getId()); //物料下面的原材料
            List<TbMatlConsumables> matlConsumables = tbMatlConsumablesMapper.selectMatlConsumables(material.getId()); //物料下面的耗材
            if (EmptyUtils.isEmpty(tbRmMatls) || EmptyUtils.isEmpty(matlConsumables))
                throw new ServiceException("物料下面不存在耗材跟原料");
            String paramsValue = paramsServiceService.get("MATL_SRC_PO").getRemark();//来源
            for (TbMatlConsumables matlConsumable : matlConsumables) {
                TbSendMatl sendMatl = new TbSendMatl();  //发料对象
                sendMatl.setPpId(plan.getId()); //生产计划id
                sendMatl.setConsumablesId(matlConsumable.getConsumables().getId());//耗材id
                sendMatl.setCreateBy(plan.getCreateBy());//创建人
                sendMatl.setMatlSrc(paramsValue);
                sendMatl.setType(1);//耗材
                if (sendMatlMapper.insert(sendMatl) == 0) throw new ServiceException("耗材添加发料单失败!");
            }
            for (TbRmMatl tbRmMatl : tbRmMatls) { //循环原材料
                TbSendMatl sendMatl = new TbSendMatl();  //发料对象
                sendMatl.setPpId(plan.getId()); //生产计划id
                sendMatl.setRmId(tbRmMatl.getRmId());//原料id
                sendMatl.setCreateBy(plan.getCreateBy());//创建人
                sendMatl.setMatlSrc(paramsValue);
                sendMatl.setType(0);//原材料
                TbPpMatlRm ppMatlRm = new TbPpMatlRm();  //添加生产计划关联物料,原材料
                ppMatlRm.setMatlId(material.getId()); //物料id
                ppMatlRm.setPpId(plan.getId());        //生产计划id
                ppMatlRm.setRmId(tbRmMatl.getRmId());     //原料id
                //添加原材料
                if (sendMatlMapper.insert(sendMatl) == 0 || tbPpMatlRmMapper.insert(ppMatlRm) == 0)
                    throw new ServiceException("原料添加发料单失败!");
            }
            return ResultUtil.success(ResultEnum.SUCCESS, "新增生产计划成功!");
        } else {
            return ResultUtil.error(ResultEnum.UNKONW_ERROR, "新增生产计划失败!");
        }

//        } else {
//            return ResultUtil.success(ResultEnum.UNKONW_ERROR, "计划数不能大于订单数!");
//        }


    }

    @Override
    @Transactional
    public int addEpt(TbOrder order) {
        TbProdPlan plan = new TbProdPlan();
        plan.setOrderId(order.getId());
        plan.setCreateBy(order.getCreateBy());
        plan.setCreateTime(order.getCreateTime());
        plan.setPlanNumber(1L);
        return mapper.insert(plan);
    }

    @Override
    @Transactional
    public Result<Object> upd(TbProdPlan plan) {
        if (plan.getPlanNumber() <= 0) {
            throw new ServiceException("计划数不能小于0!");
        }
        if (EmptyUtils.isEmpty(plan.getDelivery())) return ResultUtil.error(ResultEnum.UNKONW_ERROR, "交期不能为空");
        if (EmptyUtils.isEmpty(plan.getMechId())) return ResultUtil.error(ResultEnum.UNKONW_ERROR, "设备不能为空");
        TbOrder tbOrder = tbOrderService.checkOrderNumberUnique(plan.getOrderNumber());
        TbMaterial material = QuickQuery.byOne(tbMaterialMapper, "matl_number", plan.getMatlNumber());
        if (EmptyUtils.isNotEmpty(plan.getGroupNumber())) {
            if (EmptyUtils.isEmpty(pgService.getProcessGroupById(plan.getGroupNumber()))) {
                throw new ServiceException("工艺流程不存在!");
            }
        } else {
            return ResultUtil.error(ResultEnum.UNKONW_ERROR, "工序不能为空");
        }
        if (EmptyUtils.isEmpty(material))
            throw new ServiceException("物料不存在");
        //if (((getProds(tbOrder.getId()) - planNumber) + plan.getPlanNumber()) <= tbOrder.getOrderPcs()) {
        plan.setOrderId(tbOrder.getId());
        plan.setMatlId(material.getId());
        if (mapper.updateById(plan) > 0) {
            return ResultUtil.success(ResultEnum.SUCCESS);
        } else {
            return ResultUtil.error(ResultEnum.UNKONW_ERROR, "执行失败");
        }

        //} else {
        //return ResultUtil.success(ResultEnum.UNKONW_ERROR, "计划数不能大于订单数!");
        //}
    }

    /**
     * 删除生产计划下的耗材
     */
    public void deleteTbPpConsumables(Long ppId) {
        QueryWrapper<TbPpConsumables> qw = new QueryWrapper<>(); //查询
        qw.eq("pp_id", ppId);
        List<TbPpConsumables> tbPpConsumables = tbPpConsumablesMapper.selectList(qw);
        for (TbPpConsumables tbPpConsumable : tbPpConsumables) {
            tbPpConsumablesMapper.deleteById(tbPpConsumable.getId()); //删除
        }
    }

    @Override
    @Transactional
    public Result<Object> del(TbProdPlan plan) {
        Long id = plan.getId();
        TbProdPlan tbProdPlan = mapper.selectById(id);
        if (EmptyUtils.isNotEmpty(id)) {
            if (tbOrderMapper.selectById(tbProdPlan.getOrderId()).getOrderState() == 1) {
                return ResultUtil.error(ResultEnum.UNKONW_ERROR, "该订单已完成不能删除！");
            }
            if (EmptyUtils.isNotEmpty(mapper.prodPlanById(id))) {
                return ResultUtil.error(ResultEnum.UNKONW_ERROR, "该生产计划已经报工不能删除！");
            }
            if (tbProdPlan.getFinished() == 1) {
                return ResultUtil.error(ResultEnum.UNKONW_ERROR, "该生产计划已完成不能删除！");
            }
            deleteTbPpConsumables(id);
            mapper.deleteById(id);
            return ResultUtil.success(ResultEnum.SUCCESS, "删除生产计划成功!");
        } else {
            return ResultUtil.error(ResultEnum.UNKONW_ERROR, "缺少参数");
        }

    }

    @Override
    @Transactional
    public Result<Object> updateFinished(TbProdPlan plan) {
        if (EmptyUtils.isNotEmpty(plan.getId())) {
            plan.setFinished(1);
            mapper.updateById(plan);
            return ResultUtil.success(ResultEnum.SUCCESS, "生产计划完成!");
        } else {
            return ResultUtil.error(ResultEnum.UNKONW_ERROR, "生产计划完成失败!");
        }
    }

    @Override
    @Transactional
    public Result<Object> updateFinCount(TbProdPlan plan) {
        try {
            if (EmptyUtils.isNotEmpty(plan.getId()) || EmptyUtils.isNotEmpty(plan.getOutwardId())) { //判断id不为空进入操作
                if (EmptyUtils.isNotEmpty(plan.getId())) {
                    TbProdPlan tbProdPlan = mapper.selectById(plan.getId()); ///查询该生产计划
                    Long finCount = plan.getFpNumber() + tbProdPlan.getFinCount(); //以前的完成数加上现在过qc的数
                    tbProdPlan.setFinCount(finCount); //修改生产计划的完成数
                    if (mapper.updateById(tbProdPlan) == 0) {
                        throw new ServiceException("修改生产计划完成数失败!");
                    }
                }
                TbMaterial material = tbMaterialMapper.selectById(plan.getMatlId()); //查询到该物料
                TbMatlStore matlStore = new TbMatlStore();
                matlStore.setMatlId(material.getId()); //物料id
                matlStore.setQcReport(plan.getRemark()); //检查报告
                matlStore.setType(0);//类型
                matlStore.setFp(plan.getFpNumber()); //成品数
                matlStore.setSp(plan.getSpNumber()); //半成品数
                matlStore.setCreateBy(plan.getCreateBy()); //入库人
                Result<Object> objectResult = tbMatlStoreService.insertTbMatlStore(matlStore);
                material.setFpPcs(material.getFpPcs() + plan.getFpNumber()); //把之前物料的成品数+多出成品数
                material.setSpPcs(material.getSpPcs() + plan.getSpNumber()); //把之前物料的半成品数+多出半成品数
                if (tbMaterialMapper.updateById(material) == 0 && objectResult.getCode() != 200) {//修改数量
                    throw new ServiceException("添加入库记录失败,修改物料成品数失败!");
                } else return ResultUtil.error(ResultEnum.SUCCESS, "修改完成数成功!");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ResultUtil.error(ResultEnum.UNKONW_ERROR, "修改完成数失败!");
    }

    /**
     * 根据生产型号
     *
     * @param params
     * @return
     */
    @Override
    public Result<Object> getProdPlan(Map<String, String> params) {
        if (EmptyUtils.isNotEmpty(params.get("page")) && EmptyUtils.isNotEmpty(params.get("limit"))) {
            Page<TbProdPlan> page = new Page<>(Long.parseLong(params.get("page")), Long.parseLong(params.get("limit")));
            IPage<TbProdPlan> iPage = mapper.getProdPlan(page, params);
            List<TbProdPlan> records = iPage.getRecords(); //发料记录
            return ResultUtil.success(ResultEnum.SUCCESS, records, records.size());
        }
        return ResultUtil.error(ResultEnum.UNKONW_ERROR, "缺少参数");
    }

    @Override
    @Transactional
    public Result<Object> addConsumables(TbProdPlan prodPlan) {
        if (EmptyUtils.isEmpty(prodPlan.getId())) return ResultUtil.error(ResultEnum.UNKONW_ERROR, "请输入生产计划id");
        if (EmptyUtils.isEmpty(prodPlan.getCreateBy())) return ResultUtil.error(ResultEnum.UNKONW_ERROR, "请输入操作人");
        if (EmptyUtils.isEmpty(mapper.selectById(prodPlan.getId())))
            return ResultUtil.error(ResultEnum.UNKONW_ERROR, "请选择存在的生产计划");
        addTbPpConsumables(prodPlan); //添加耗材
        return ResultUtil.success(ResultEnum.SUCCESS, "执行成功！");
    }

    public String productionModel(String createBy) {
        try {
            lock.lock();
            return existModel(createBy);
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        } finally {
            lock.unlock();
        }
    }

    //生成型号
    public String model(String createBy) {
        int arrIndex = new Random().nextInt(arr.length);
        int number = new Random().nextInt(10 * 1000);
        modelIndex = modelIndex + 1;
        String model;
        if (EmptyUtils.isNotEmpty(createBy)) {
            model = createBy + arr[arrIndex] + number + modelIndex;
        } else {
            model = arr[arrIndex] + number + modelIndex;
        }
        return model;
    }

    public String existModel(String createBy) {
        while (true) {
            String model = model(createBy);
            QueryWrapper<TbProdPlan> qw = new QueryWrapper<>();
            qw.eq("spec_number", model);
            if (EmptyUtils.isEmpty(mapper.selectOne(qw))) {
                return model;
            }
        }
    }

    /**
     * 生产计划添加耗材
     */
    private void addTbPpConsumables(TbProdPlan plan) {
        List<TbPpConsumables> ppConsumablesList = plan.getPpConsumablesList(); //耗材集合
        if (EmptyUtils.isNotEmpty(ppConsumablesList)) {
            deleteTbPpConsumables(plan.getId());
            String paramsValue = paramsServiceService.get("MATL_SRC_PO").getRemark();//来源
            TbConsumables tbConsumables;  //耗材对象
            for (TbPpConsumables tbPpConsumables : ppConsumablesList) {
                int result = 0;//0为不存在 1 为存在
                Long consumablesId = tbPpConsumables.getId(); //耗材id
                Integer qty = tbPpConsumables.getQty(); //耗材比数
                Integer count = tbPpConsumables.getCount(); //耗材比数
                tbConsumables = tbConsumablesMapper.selectById(consumablesId); //查询出来耗材记录
                if (EmptyUtils.isEmpty(tbConsumables)) throw new ServiceException("请选择存在的耗材!");
                else if (EmptyUtils.isEmpty(qty) || qty == 0 || EmptyUtils.isEmpty(count) || count == 0)  //判断消耗数量
                    throw new ServiceException("请输入耗材比数");
//                if (qty > (EmptyUtils.isEmpty(tbConsumables.getNumber()) ? 0 : tbConsumables.getNumber()))
//                    throw new ServiceException("耗材：" + tbPpConsumables.getName() + "数量不能大于原先数量!");
                List<TbPpConsumables> ppConsumables = ppConsumablesList(plan.getId());//查询下面的耗材
                //判断数量不一样的时候进行循环判断
                if (ppConsumables.size() != ppConsumablesList.size()) {
                    for (TbPpConsumables ppConsumable : ppConsumables) {//循环之前的耗材
                        if (ppConsumable.getConsumablesId().equals(consumablesId)) {//如果耗材有的话就不添加
                            result = 1;//为存在
                            break;
                        }
                    }
                    if (result == 0) {  //不存在就添加
                        tbPpConsumables.setConsumablesId(consumablesId); //耗材数量
                        tbPpConsumables.setPpId(plan.getId());//生产计划id
                        tbPpConsumables.setId(null);//id
                        if (tbPpConsumablesMapper.insert(tbPpConsumables) > 0) { //添加耗材记录
                            TbSendMatl tbSendMatl = new TbSendMatl();  //发料对象
                            tbSendMatl.setPpId(plan.getId()); //生产计划id
                            tbSendMatl.setMatlSrc(paramsValue);//物料来源
                            tbSendMatl.setConsumablesId(tbPpConsumables.getConsumablesId());//耗材id
                            tbSendMatl.setCreateBy(plan.getCreateBy());//创建人
                            tbSendMatl.setType(1);//耗材
                            //添加耗材发料
                            if (sendMatlMapper.insert(tbSendMatl) == 0)
                                throw new ServiceException("添加耗材发料失败");
                        }
                    }
                }
            }
        }
    }

    /**
     * 根据生产计划id查询关联的耗材
     *
     * @param ppId
     * @return
     */
    private List<TbPpConsumables> ppConsumablesList(Long ppId) {
        QueryWrapper<TbPpConsumables> qw = new QueryWrapper<>();
        qw.eq("pp_id", ppId);
        return tbPpConsumablesMapper.selectList(qw);
    }
}
